﻿using System;
using System.Collections;
using System.IO;
using RazorEngine.Configuration;
using RazorEngine.Templating;
using SW.Lite.Infrastructure.Exception;
using SW.Lite.Infrastructure.Helpers;

namespace SW.Lite.Core.Template.Razor
{
    public class TemplateParser : ITemplateParser
    {
        private readonly DynamicViewBag _bag;
        private readonly IRazorEngineService _engine;

        public TemplateParser()
        {
            var config = new TemplateServiceConfiguration { BaseTemplateType = typeof(Template<>) };
            _engine = RazorEngineService.Create(config);
            _bag = new DynamicViewBag();
        }

        /// <summary>
        ///     Gets the absolute template folder.
        /// </summary>
        /// <remarks>
        ///     Q: why use 'AppDomain' instead of 'HttpContext'?
        ///     A:In a aysnc situation, HttpContext.Current = null, however,'AppDomain.CurrentDomain.BaseDirectory' get a not null
        ///     value
        /// </remarks>
        public string TemplateFolder
        {
            get
            {
                return Path.Combine(AppDomain.CurrentDomain.BaseDirectory, ConfigHelper.Instance.Template.Folder,
                    ConfigHelper.Instance.Template.RazorFolder);
            }
        }

        /// <summary>
        ///     Parses the file.
        /// </summary>
        /// <param name="filePath">The file path.</param>
        /// <returns>System.String.</returns>
        public string ParseFile(string filePath)
        {
            return ParseFile<string>(filePath, null);
        }

        /// <summary>
        ///     Parses the file.
        /// </summary>
        /// <typeparam name="TModel">The type of the t model.</typeparam>
        /// <param name="filePath">The file path.</param>
        /// <param name="model">The model.</param>
        public string ParseFile<TModel>(string filePath, TModel model)
        {
            return ParseFile(filePath, model, null);
        }

        /// <summary>
        ///     Parses the specified template content.
        /// </summary>
        /// <param name="templateContent">Content of the template.</param>
        public string Parse(string templateContent)
        {
            return Parse<string>(templateContent, null);
        }

        /// <summary>
        ///     Parses the specified template content.
        /// </summary>
        /// <typeparam name="TModel">The type of the t model.</typeparam>
        /// <param name="templateContent">Content of the template.</param>
        /// <param name="model">The model.</param>
        public string Parse<TModel>(string templateContent, TModel model)
        {
            return Parse(templateContent, model, null);
        }

        /// <summary>
        ///     Parses the file.
        /// </summary>
        /// <typeparam name="TModel">The type of the t model.</typeparam>
        /// <param name="filePath">The file path.</param>
        /// <param name="model">The model.</param>
        /// <param name="context">The context.</param>
        /// <exception cref="CodeException">0x002001</exception>
        public string ParseFile<TModel>(string filePath, TModel model, Hashtable context)
        {
            if (context != null)
            {
                foreach (string item in context.Keys)
                    _bag.AddValue(item, context[item]);
            }
            try
            {
                using (
                    var fileStream = new FileStream(Path.Combine(TemplateFolder, filePath), FileMode.Open,
                        FileAccess.Read))
                {
                    using (var reader = new StreamReader(fileStream))
                    {
                        var templateContent = reader.ReadToEnd();
                        if (ConfigHelper.Instance.DebugMode)
                            return _engine.RunCompile(templateContent, filePath, typeof(TModel), model, _bag);

                        return _engine.IsTemplateCached(filePath, typeof(TModel))
                            ? _engine.Run(filePath, typeof(TModel))
                            : _engine.RunCompile(templateContent, filePath, typeof(TModel), model, _bag);
                    }
                }
            }
            catch (Exception ex)
            {
                throw new CodeException(0x002001, "", ex);
            }
        }

        /// <summary>
        ///     Parses the specified template content.
        /// </summary>
        /// <typeparam name="TModel">The type of the t model.</typeparam>
        /// <param name="templateContent">Content of the template.</param>
        /// <param name="model">The model.</param>
        /// <param name="context">The context.</param>
        /// <exception cref="CodeException">0x002001</exception>
        public string Parse<TModel>(string templateContent, TModel model, Hashtable context)
        {
            if (context != null)
            {
                foreach (string item in context.Keys)
                    _bag.AddValue(item, context[item]);
            }
            try
            {
                return _engine.RunCompile(templateContent, RandomHelper.Instance.RandomString("********"),
                    typeof(TModel), model, _bag);
            }
            catch (Exception ex)
            {
                throw new CodeException(0x002001, "", ex);
            }
        }

        public void ClearCache()
        {
            throw new NotImplementedException();
        }
    }
}